﻿module utils.fileWrapper.File;
import utils.fileWrapper.Exceptions;
import utils.fileWrapper.Interfaces;
import std.stream;


alias std.stream.FileMode FileMode;


template RetT(T) {
	static if (is(T == delegate)) {
		alias void RetT;
	} else {
		alias T RetT;
	}
}


RetT!(T) deExceptionize(T)(lazy T dg) {
		try{
		static if (is(T == delegate)) {
			dg()();
		}
		else {
			return dg();
		}
		} catch (ReadException e){
			throw new WrapperReadException(e.toString());
		} catch (WriteException e){
			throw new WrapperWriteException(e.toString());
		} catch (SeekException e){
			throw new WrapperSeekException(e.toString());
		} catch (StreamException e){
			throw new WrapperException(e.toString());
		}
}


class File: InputWrapper, OutputWrapper{
	private {
		char[] path;
		BufferedFile file;
	}

	
	this(char[] filename, FileMode mode = FileMode.In, uint bufferSize = 8192u){
		deExceptionize({
				
				path=filename.dup;
				file=new BufferedFile(filename, mode, bufferSize);				
 		});
	}

	this() {
		deExceptionize({
				file=new BufferedFile();				
 		});
	}

	~this() {}
	
	/*
	TODO if necessery
	
	this(File f, uint bufferSize = 8192u){
		deExceptionize({
				path~="unknown";
				file=new BufferedFile(f, bufferSize);				
 		});
	}

	 this(HANDLE hFile, FileMode mode, uint buffersize){
		deExceptionize({
				path~="unknown";
				file=new BufferedFile(f, bufferSize);				
 		});
	} */
	
	void readExact(void* buffer, uint size) { 
		assert(file !is null);
		return deExceptionize!(void)( file.readExact(buffer, size)); 
	}
	
	uint read(ubyte[] buffer){
		return deExceptionize!(uint)(file.read(buffer));
	}
	
	void read(out byte x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out ubyte x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out short x){
		return deExceptionize!(void)(file.read(x));
	}
	void read(out ushort x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out int x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out uint x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out long x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out ulong x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out float x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out double x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out real x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out ifloat x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out idouble x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out ireal x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out cfloat x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out cdouble x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out creal x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out char x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out wchar x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out dchar x){
		return deExceptionize!(void)(file.read(x));
	}
	
	void read(out char[] s){
		return deExceptionize!(void)(file.read(s));
	}
	
	void read(out wchar[] s){
		return deExceptionize!(void)(file.read(s));
	}
	
	char[] readLine(){
		return deExceptionize!(char[])(file.readLine());
	}
	
	char[] readLine(char[] result){
		return deExceptionize!(char[])(file.readLine(result));
	}
	
	wchar[] readLineW(){
		return deExceptionize!(wchar[])(file.readLineW());
	}
	
	wchar[] readLineW(wchar[] result){
		return deExceptionize!(wchar[])(file.readLineW(result));
	}
	
	int opApply(int delegate(inout char[] line) dg){
		return deExceptionize!(int)(file.opApply(dg));
	}
	
	int opApply(int delegate(inout ulong n, inout char[] line) dg){
		return deExceptionize!(int)(file.opApply(dg));
	}
	
	int opApply(int delegate(inout wchar[] line) dg){
		return deExceptionize!(int)(file.opApply(dg));
	}
	
	int opApply(int delegate(inout ulong n, inout wchar[] line) dg){
		return deExceptionize!(int)(file.opApply(dg));
	}
	
	char[] readString(uint length){
		return deExceptionize!(char[])(file.readString(length));
	}
	
	wchar[] readStringW(uint length){
		return deExceptionize!(wchar[])(file.readStringW(length));
	}
	
	char getc(){
		return deExceptionize!(char)(file.getc);
	}
	
	wchar getcw(){
		return deExceptionize!(wchar)(file.getcw);
	}
	
	char ungetc(char c){
		return deExceptionize!(char)(file.ungetc(c));
	}
	
	wchar ungetcw(wchar c){
		return deExceptionize!(wchar)(file.ungetcw(c));
	}
	
	int vreadf(TypeInfo[] arguments, void* args){
		return deExceptionize!(int)(file.vreadf(arguments, args));
	}
	
	uint available(){
		return deExceptionize!(uint)(file.available());
	}
	
	bool eof(){
		return deExceptionize!(bool) (file.eof());
	}
	bool isOpen(){
		return deExceptionize!(bool) (file.isOpen());
	}

	void writeExact(void* buffer, uint size){
		return deExceptionize!(void) (file.writeExact(buffer,size));
	}
	
	uint write(ubyte[] buffer){
		return deExceptionize!(uint) (file.write(buffer));
	}
	
	void write(byte x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(ubyte x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(short x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(ushort x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(int x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(uint x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(long x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(ulong x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(float x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(double x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(real x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(ifloat x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(idouble x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(ireal x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(cfloat x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(cdouble x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(creal x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(char x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(wchar x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(dchar x){
		return deExceptionize!(void) (file.write(x));
	}
	
	void write(char[] s){
		return deExceptionize!(void) (file.write(s));
	}
	
	void write(wchar[] s){
		return deExceptionize!(void) (file.write(s));
	}
	
	void writeLine(char[] s){
		return deExceptionize!(void) (file.writeLine(s));
	}
	
	void writeLineW(wchar[] s){
		return deExceptionize!(void) (file.writeLineW(s));
	}
	
	void writeString(char[] s){
		return deExceptionize!(void) (file.writeString(s));
	}
	
	void writeStringW(wchar[] s){
		return deExceptionize!(void) (file.writeStringW(s));
	}
	
	void flush(){
		return deExceptionize!(void) (file.flush());
	}
	
	void close(){
		return deExceptionize!(void) (file.close());
	}
	
	void open(char[] filename, FileMode mode = cast(FileMode)1){
		return deExceptionize!(void)({
			path=filename.dup;
			file.open(path,mode);
		});
	}

	void create(char[] filename, FileMode mode = cast(FileMode)2){
		return deExceptionize!(void)({
			path=filename.dup;
			file.create(path,mode);
		});
	}

	ulong seek(long offset, SeekPos whence){
		return deExceptionize!(ulong)(file.seek(offset,whence));
	}

	ulong seekSet(long offset){
		return deExceptionize!(ulong)(file.seekSet(offset));
	}
	
	ulong seekCur(long offset){
		return deExceptionize!(ulong)(file.seekCur(offset));
	}
	
	ulong seekEnd(long offset){
		return deExceptionize!(ulong)(file.seekEnd(offset));
	}
	
}